package gdconf

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"io"
	"math"
	"os"
	"runtime"
	"strings"
	"time"

	"server_cluster/common/logger"

	"github.com/jszwec/csvutil"
	"gorm.io/gorm"
)

// 游戏数据配置表

const (
	DbInsertBatchSize = 100
)

var CONF *GameDataConfig = nil
var CONF_RELOAD *GameDataConfig = nil

type GameDataConfigMaps struct {
	// 配置表数据
	RoleTalentConfigMap             map[int32]*RoleTalentConfig                       // 角色天赋
	RoleTalentEffectGroupConfigMap  map[int32]map[int32]*RoleTalentEffectGroupConfig  // 角色天赋效果组
	RoleStarConfigMap               map[int32]map[int32]*RoleStarConfig               // 角色星级
	BattleSkillCardConfigMap        map[int32]*BattleSkillCardConfig                  // 战斗技能卡
	BattleSubSkillConfigMap         map[int32]*BattleSubSkillConfig                   // 战斗子技能
	BattleSubSkillEffectConfigMap   map[int32]*BattleSubSkillEffectConfig             // 战斗子技能效果
	RoleConfigMap                   map[int32]*RoleConfig                             // 角色
	ItemConfigMap                   map[int32]*ItemConfig                             // 道具
	ConstConfigMap                  map[string]*ConstConfig                           // 常量
	RoleLevelConfigMap              map[int32]map[int32]*RoleLevelConfig              // 角色等级
	RolePromoteConfigMap            map[int32]map[int32]*RolePromoteConfig            // 角色等阶
	WeaponConfigMap                 map[int32]*WeaponConfig                           // 武器
	WeaponLevelConfigMap            map[int32]map[int32]*WeaponLevelConfig            // 武器等级
	WeaponPromoteConfigMap          map[int32]map[int32]*WeaponPromoteConfig          // 武器等阶
	WeaponStarConfigMap             map[int32]map[int32]*WeaponStarConfig             // 武器星级
	SceneConfigMap                  map[int32]*SceneConfig                            // 场景
	HomeBuildingConfigMap           map[int32]*HomeBuildingConfig                     // 家园建筑
	BattleGroupConfigMap            map[int32]*BattleGroupConfig                      // 战斗组
	BattleMonsterConfigMap          map[int32]*BattleMonsterConfig                    // 战斗怪物
	GadgetConfigMap                 map[int32]*GadgetConfig                           // 场景交互物件
	HomeBuildingLevelGroupConfigMap map[int32]map[int32]*HomeBuildingLevelGroupConfig // 家园建筑等级组
	HomeLevelConfigMap              map[int32]*HomeLevelConfig                        // 家园等级
	ItemUseConfigMap                map[int32]*ItemUseConfig                          // 道具使用
	PlayerLevelConfigMap            map[int32]*PlayerLevelConfig                      // 玩家等级
	CodexConfigMap                  map[int32]*CodexConfig                            // 图鉴
	CodexConfigOtherIdMap           map[int32]*CodexConfig                            // 图鉴关联id
	ShopConfigMap                   map[int32]*ShopConfig                             // 商店
	ItemResolveConfigMap            map[int32]*ItemResolveConfig                      // 道具分解
	ItemComposeConfigMap            map[int32]*ItemComposeConfig                      // 道具合成
	NpcConfigMap                    map[int32]*NpcConfig                              // 场景npc
	BattleConfigMap                 map[int32]*BattleConfig                           // 战斗
	DungeonActivityConfigMap        map[int32]*DungeonActivityConfig                  // 地牢活动
	DungeonConfigMap                map[int32]*DungeonConfig                          // 地牢
	ActivityTaskConfigMap           map[int32]*ActivityTaskConfig                     // 活动任务
	OpenStateConfigMap              map[int32]*OpenStateConfig                        // 功能开放
	SceneDataMap                    map[int32]*SceneData                              // 场景数据
	TowerConfigMap                  map[int32]*TowerConfig                            // 爬塔
	GadgetActiveConfig              map[int32]*GadgetActiveConfig                     // 宝箱
	SignInConfigMap                 map[int32]*SignInConfig                           // 每日签到
	EquipConfigMap                  map[int32]*EquipConfig                            // 装备
	EquipJewelConfigMap             map[int32]*EquipJewelConfig                       // 装备宝石
	EquipLevelConfigMap             map[int32]*EquipLevelConfig                       // 装备等级
	EquipSkillConfigMap             map[int32]*EquipSkillConfig                       // 装备技能
	EquipSkillGroupConfigMap        map[int32]*EquipSkillGroupConfig                  // 装备技能组
	FishConfigMap                   map[int32]*FishConfig                             // 鱼
	FishBaitConfigMap               map[int32]*FishBaitConfig                         // 鱼饵
	FishRodConfigMap                map[int32]*FishRodConfig                          // 鱼竿
	FishPointConfigMap              map[int32]*FishPointConfig                        // 钓鱼点
	ActivityConfigMap               map[int32]*ActivityConfig                         // 活动
	ActivityParamConfigMap          map[int32]*ActivityParamConfig                    // 活动参数
	HomeFarmSeedConfigMap           map[int32]*HomeFarmSeedConfig                     // 家园农田种子
	CaptainSkillConfigMap           map[int32]*CaptainSkillConfig                     // 队长技能
	CaptainSkillLevelConfigMap      map[int32]map[int32]*CaptainSkillLevelConfig      // 队长技能等级
	MailConfigMap                   map[int32]*MailConfig                             // 邮件
	GachaMap                        map[int32]*GachaConfig                            // 抽卡
	GachaPoolMap                    map[int32]*GachaPoolConfig                        // 抽卡蛋池
	GachaProbMap                    map[int32]*GachaProbConfig                        // 抽卡概率
	GachaProb2Map                   map[int32]*GachaProb2Config                       // 抽卡概率2
	//RewardMap                       map[int32]*RewardConfig                           // 奖励配置
	ParentQuestMap          map[int32]*ConfigParentQuest    // 任务
	QuestMap                map[int32]*ConfigQuest          // 任务
	TrailRoleConfigMap      map[int32]*TrailRoleConfig      // 试用角色
	TrailRoleGroupConfigMap map[int32]*TrailRoleGroupConfig // 试用角色组
}
type GameDataConfig struct {
	Db             *gorm.DB
	CsvPathPrefix  string
	JsonPathPrefix string
	GameDataMaps   GameDataConfigMaps
}

func SaveGameDataConfig(path string, db *gorm.DB) {
	CONF_RELOAD = new(GameDataConfig)
	CONF_RELOAD.Db = db
	dirInfo, err := os.Stat(path)
	if err != nil || !dirInfo.IsDir() {
		info := fmt.Sprintf("open game data config dir error: %v", err)
		panic(info)
	}
	CONF_RELOAD.CsvPathPrefix = path + "/"
	CONF_RELOAD.JsonPathPrefix = path + "/Json"
	CONF_RELOAD.saveAll()
	logger.Info("save all game data config finish")
}

func LoadGameDataConfig(db *gorm.DB) {
	CONF = new(GameDataConfig)
	CONF.Db = db
	startTime := time.Now().Unix()
	CONF.loadAll()
	endTime := time.Now().Unix()
	runtime.GC()
	logger.Info("load all game data config finish, cost: %v(s)", endTime-startTime)
}

func ReloadGameDataConfig(db *gorm.DB) {
	CONF_RELOAD = new(GameDataConfig)
	CONF_RELOAD.Db = db
	startTime := time.Now().Unix()
	CONF_RELOAD.loadAll()
	endTime := time.Now().Unix()
	runtime.GC()
	logger.Info("reload all game data config finish, cost: %v(s)", endTime-startTime)
}

func ReplaceGameDataConfig() {
	CONF = CONF_RELOAD
}

func (g *GameDataConfig) saveAll() {
	g.saveRoleTalentConfig()             // 角色天赋
	g.saveRoleTalentEffectGroupConfig()  // 角色天赋效果组
	g.saveRoleStarConfig()               // 角色星级
	g.saveBattleSkillCardConfig()        // 战斗技能卡
	g.saveBattleSubSkillConfig()         // 战斗子技能
	g.saveBattleSubSkillEffectConfig()   // 战斗子技能效果
	g.saveRoleConfig()                   // 角色
	g.saveItemConfig()                   // 道具
	g.saveConstConfig()                  // 常量
	g.saveRoleLevelConfig()              // 角色等级
	g.saveRolePromoteConfig()            // 角色等阶
	g.saveWeaponConfig()                 // 武器
	g.saveWeaponLevelConfig()            // 武器等级
	g.saveWeaponPromoteConfig()          // 武器等阶
	g.saveWeaponStarConfig()             // 武器星级
	g.saveSceneConfig()                  // 场景
	g.saveHomeBuildingConfig()           // 家园建筑
	g.saveBattleGroupConfig()            // 战斗组
	g.saveBattleMonsterConfig()          // 战斗怪物
	g.saveGadgetConfig()                 // 场景交互物件
	g.saveHomeBuildingLevelGroupConfig() // 家园建筑等级组
	g.saveHomeLevelConfig()              // 家园等级
	g.saveItemUseConfig()                // 道具使用
	g.savePlayerLevelConfig()            // 玩家等级
	g.saveCodexConfig()                  // 图鉴
	g.saveShopConfig()                   // 商店
	g.saveItemResolveConfig()            // 道具分解
	g.saveItemComposeConfig()            // 道具合成
	g.saveNpcConfig()                    // 场景npc
	g.saveBattleConfig()                 // 战斗
	g.saveDungeonActivityConfig()        // 地牢活动
	g.saveDungeonConfig()                // 地牢
	g.saveActivityTaskConfig()           // 活动任务
	g.saveOpenStateConfig()              // 功能开放
	g.saveSceneData()                    // 场景数据
	g.saveTowerConfig()                  // 爬塔
	g.saveGadgetActiveConfig()           // 宝箱
	g.saveSignInConfig()                 // 每日签到
	g.saveEquipConfig()                  // 装备
	g.saveEquipJewelConfig()             // 装备宝石
	g.saveEquipLevelConfig()             // 装备等级
	g.saveEquipSkillConfig()             // 装备技能
	g.saveEquipSkillGroupConfig()        // 装备技能
	g.saveFishConfig()                   // 鱼
	g.saveFishBaitConfig()               // 鱼饵
	g.saveFishRodConfig()                // 鱼竿
	g.saveFishPointConfig()              // 钓鱼点
	g.saveActivityConfig()               // 活动
	g.saveActivityParamConfig()          // 活动参数
	g.saveHomeFarmSeedConfig()           // 家园农田种子
	g.saveCaptainSkillConfig()           // 队长技能
	g.saveCaptainSkillLevelConfig()      // 队长技能等级
	g.saveMailConfig()                   // 邮件
	g.saveGacha()                        //	抽卡
	g.saveGachaPool()                    //	抽卡蛋池
	g.saveGachaProb()                    // 抽卡概率
	g.saveGachaProb2()                   // 抽卡概率2
	//g.saveReward()                       // 奖励配置
	g.saveParentQuest()    // 父任务
	g.saveQuest()          // 任务
	g.saveTrailRole()      // 试用角色
	g.saveTrailRoleGroup() // 试用角色组
}

func (g *GameDataConfig) loadAll() {
	g.loadRoleTalentConfig()             // 角色天赋
	g.loadRoleTalentEffectGroupConfig()  // 角色天赋效果组
	g.loadRoleStarConfig()               // 角色星级
	g.loadBattleSkillCardConfig()        // 战斗技能卡
	g.loadBattleSubSkillConfig()         // 战斗子技能
	g.loadBattleSubSkillEffectConfig()   // 战斗子技能效果
	g.loadRoleConfig()                   // 角色
	g.loadItemConfig()                   // 道具
	g.loadConstConfig()                  // 常量
	g.loadRoleLevelConfig()              // 角色等级
	g.loadRolePromoteConfig()            // 角色等阶
	g.loadWeaponConfig()                 // 武器
	g.loadWeaponLevelConfig()            // 武器等级
	g.loadWeaponPromoteConfig()          // 武器等阶
	g.loadWeaponStarConfig()             // 武器星级
	g.loadSceneConfig()                  // 场景
	g.loadHomeBuildingConfig()           // 家园建筑
	g.loadBattleGroupConfig()            // 战斗组
	g.loadBattleMonsterConfig()          // 战斗怪物
	g.loadGadgetConfig()                 // 场景交互物件
	g.loadHomeBuildingLevelGroupConfig() // 家园建筑等级组
	g.loadHomeLevelConfig()              // 家园等级
	g.loadItemUseConfig()                // 道具使用
	g.loadPlayerLevelConfig()            // 玩家等级
	g.loadCodexConfig()                  // 图鉴
	g.loadShopConfig()                   // 商店
	g.loadItemResolveConfig()            // 道具分解
	g.loadItemComposeConfig()            // 道具合成
	g.loadNpcConfig()                    // 场景npc
	g.loadBattleConfig()                 // 战斗
	g.loadDungeonActivityConfig()        // 地牢活动
	g.loadDungeonConfig()                // 地牢
	g.loadActivityTaskConfig()           // 活动任务
	g.loadOpenStateConfig()              // 功能开放
	g.loadSceneData()                    // 场景数据
	g.loadTowerConfig()                  // 爬塔
	g.loadGadgetActiveConfig()           // 宝箱
	g.loadSignInConfig()                 // 每日签到
	g.loadEquipConfig()                  // 装备
	g.loadEquipJewelConfig()             // 装备宝石
	g.loadEquipLevelConfig()             // 装备等级
	g.loadEquipSkillConfig()             // 装备技能
	g.loadEquipSkillGroupConfig()        // 装备技能
	g.loadFishConfig()                   // 鱼
	g.loadFishBaitConfig()               // 鱼饵
	g.loadFishRodConfig()                // 鱼竿
	g.loadFishPointConfig()              // 钓鱼点
	g.loadActivityConfig()               // 活动
	g.loadActivityParamConfig()          // 活动参数
	g.loadHomeFarmSeedConfig()           // 家园农田种子
	g.loadCaptainSkillConfig()           // 队长技能
	g.loadCaptainSkillLevelConfig()      // 队长技能等级
	g.loadMailConfig()                   // 邮件
	g.loadGachaConfig()                  // 抽卡
	g.loadGachaPoolConfig()              // 抽卡蛋池
	g.loadGachaProbConfig()              // 抽卡概率
	g.loadGachaProb2Config()             // 抽卡概率2
	//g.loadRewardConfig()                 // 奖励配置
	g.loadQuestConfig()          // 任务
	g.loadParentQuestConfig()    // 父任务
	g.loadTrailRoleConfig()      // 试用角色
	g.loadTrailRoleGroupConfig() // 试用角色组
}

func readTable[T any](tablePath string) []*T {
	fileData, err := os.ReadFile(tablePath)
	if err != nil {
		logger.Error("找不到配置表:%v", tablePath)
		return nil
	}
	// 去除UTF8的BOM头
	if fileData[0] == 0xEF && fileData[1] == 0xBB && fileData[2] == 0xBF {
		fileData = fileData[3:]
	}
	lineList := make([]string, 0)
	var lineTemp strings.Builder
	skipLF := false
	for _, c := range fileData {
		if !skipLF && c == '\n' {
			lineList = append(lineList, lineTemp.String())
			lineTemp.Reset()
			continue
		}
		// 处理表头的行内换行
		if c == '"' {
			skipLF = !skipLF
		}
		lineTemp.WriteByte(c)
	}
	// 特殊处理常量表的表头
	if _, ok := any(new(T)).(*ConstConfig); ok {
		lineList = append([]string{""}, lineList...)
	}
	if len(lineList) < 4 {
		info := fmt.Sprintf("table format error, tablePath: %v", tablePath)
		panic(info)
	}
	var standardCsvData strings.Builder
	for index, line := range lineList {
		// 去除第一三四行的内容变成标准格式的csv
		if index == 0 || index == 2 || index == 3 {
			continue
		}
		// 去除第一列为空的行
		if len(line) == 0 || line[0] == ',' {
			continue
		}
		standardCsvData.WriteString(line)
		standardCsvData.WriteString("\n")
	}
	// csv解析
	reader := csv.NewReader(bytes.NewBuffer([]byte(standardCsvData.String())))
	reader.Comma = ','
	reader.LazyQuotes = true
	dec, err := csvutil.NewDecoder(reader)
	if err != nil {
		info := fmt.Sprintf("create decoder error: %v, tablePath: %v", err, tablePath)
		panic(info)
	}
	list := make([]*T, 0)
	for {
		t := new(T)
		err := dec.Decode(t)
		if err == io.EOF {
			break
		}
		if err != nil {
			info := fmt.Sprintf("decode file error: %v, tablePath: %v", err, tablePath)
			panic(info)
		}
		list = append(list, t)
	}
	return list
}

func saveTableToDb[T any](db *gorm.DB, list []*T) {
	if db.Migrator().HasTable(new(T)) {
		err := db.Migrator().DropTable(new(T))
		if err != nil {
			panic(err)
		}
	}
	err := db.Set("gorm:table_options", "ENGINE=MyISAM").Migrator().CreateTable(new(T))
	if err != nil {
		panic(err)
	}
	listLength := len(list)
	numBatch := int(math.Ceil(float64(listLength) / float64(DbInsertBatchSize)))
	for i := 0; i < numBatch; i++ {
		from := i * DbInsertBatchSize
		to := int(math.Min(float64((i+1)*DbInsertBatchSize), float64(listLength)))
		batch := list[from:to]
		err = db.CreateInBatches(batch, len(batch)).Error
		if err != nil {
			panic(err)
		}
	}
}

func loadTableFromDb[T any](db *gorm.DB) []*T {
	var list []*T = nil
	err := db.Find(&list).Error
	if err != nil {
		panic(err)
	}
	return list
}
